package com.ww.java.generic.wildcard;

import java.util.Arrays;
import java.util.List;

public class GenericReading {

	static <T> T readExact(List<T> list) {
		return list.get(0);
	}
	
	static List<Apple> apples = Arrays.asList(new Apple());
	
	static List<Fruit> fruit = Arrays.asList(new Fruit());
	
	@SuppressWarnings("unused")
	static void f1() {
		Apple a =  readExact(apples);
		Fruit f = readExact(fruit);
		f = readExact(apples);
	}
	
	/**
	 * 如果有一个泛型类，那么当你创建这个类的实例时，要为这个类确定参数，就像在f2()中看到的，
	 * fruitReader实例可以从List<Fruit>中读取一个Fruit，因为这就是它的确切类型。但是List<Apple>
	 * 还应该产生Fruit对象，而fruitReader不允许这么做。
	 * @param <T>
	 */
	static class Reader<T> {
		T readExact(List<T> list) {
			return list.get(0);
		}
	}
	
	@SuppressWarnings("unused")
	static void f2() {
		Reader<Fruit> fruitReader = new Reader<>();
		Fruit f = fruitReader.readExact(fruit);
		// The method readExact(List<Fruit>) in the type GenericReading.Reader<Fruit> is not applicable for the arguments (List<Apple>)
//		fruitReader.readExact(apples);
	}
	
	/**
	 * 逆变
	 * 
	 * 从这个列表中读取一个T是安全的（你知道在这个列表中的所有对象至少是一个T，并且可能是从T导出的某种对象）
	 * @param <T>
	 */
	static class CovariantReader<T> {
		T readCovariant(List<? extends T> list) {
			return list.get(0);
		}
	}
	
	@SuppressWarnings("unused")
	static void f3() {
		CovariantReader<Fruit> fruitReader = new CovariantReader<>();
		Fruit f = fruitReader.readCovariant(fruit);
		Fruit a = fruitReader.readCovariant(apples);
	}
	
	public static void main(String[] args) {
		f1();
		f2();
		f3();
	}
}
